package com.zlj.jdbc.threadLocal;

import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

/**
 * ThreadLocal对象的用法：
 * 这个对象只有三个方法：
 * 1、get();
 * 2、set();
 * 3、remove();
 * 
 * 1.ThreadLocal用来解决多线程程序的并发问题
   2.ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,
     ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本.
   3.从线程的角度看，目标变量就象是线程的本地变量，这也是类名中“Local”所要表达的意思。
   4.线程局部变量并不是Java的新发明,Java没有提供在语言级支持(语法上),而是变相地通过ThreadLocal的类提供支持.
   5.ThreadLocal类中的方法:(JDK5版本之后支持泛型)
	    void set(T value)
	          将此线程局部变量的当前线程副本中的值设置为指定值
	    void remove()
	          移除此线程局部变量当前线程的值
	    protected T initialValue()
	          返回此线程局部变量的当前线程的“初始值”
	    T get()
	          返回此线程局部变量的当前线程副本中的值
   6.ThreadLocal的原理:
	   ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单：在ThreadLocal类中有一个Map，
	        用于存储每一个线程的变量副本，Map中元素的键为线程对象，而值对应线程的变量副本
 * @author bashen
 *
 */
public class ThreadLocalDemo {

	@Test
	public void test01() {
		final ThreadLocal<String> t1 = new ThreadLocal<String>();
		//t1.set("hello");  //设置值
		//String s = t1.get();  //获取值
		//t1.remove();    //移除
		//System.out.println(s);   //hello
		
		//hello : Thread[main,5,main]
		//System.out.println(t1.get() + " : " + Thread.currentThread());  
		
		//写另一个线程对其进行取操作,因为此时已不是同一个线程，所以获取不到
		//内部类访问外部类变量要加final
		new Thread() {
            public void run() {
            	t1.set("内部类进行存储！");
            	//null : Thread[Thread-0,5,main]
            	System.out.println("内部类：" + t1.get() + " : " + Thread.currentThread()); 
            };			
		}.start();
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(t1.get() + " : " + Thread.currentThread());  
	}
	
	/**
	 * test02方法等价于test01方法
	 */
	@Test
	public void test02() {
		final Map<Thread,String> map = new HashMap<Thread,String>();
		map.put(Thread.currentThread(), "hello");
		System.out.println(map.get(Thread.currentThread()));  //hello
		/**
		 * 因为两个Thread不一样，所以导致第一个Thread存进去可以取出来，但是第二个Thread取不出来
		 */
		new Thread() {
			public void run() {
				System.out.println(map.get(Thread.currentThread()));  //null
			};
		}.start();
	}
}

/**
 * ThreadLocal的内部是一个Map
 * @author bashen
 *
 * @param <T>
 */
class ThreadLocal1<T> {
	private Map<Thread,T> map = new HashMap<Thread,T>();
	
	public void set(T data) {
		//使用当前线程做key
		map.put(Thread.currentThread(), data);
	}
	
	public T get() {
		return map.get(Thread.currentThread());
	}
	
	public void remove() {
		map.remove(Thread.currentThread());
	}
}